#include <linux/module.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/io.h>
#include <linux/uaccess.h>
#include <linux/gpio.h>
#include <linux/irq.h>        // 包含了mach/irqs.h
#include <linux/interrupt.h>
#include <linux/gpio/machine.h>
#include <mach/gpio-samsung.h>
#include <linux/input.h>
#include <linux/timer.h>

/*
 全局静态变量：希望全局变量仅限于在本源文件中使用，在其他源文件中不能引用，也就是说限制其作用域只在
 定义该变量的源文件内有效，而在同一源程序的其他源文件中不能使用
 */
#define __IRQT_FALEDGE IRQ_TYPE_EDGE_FALLING
#define __IRQT_RISEDGE IRQ_TYPE_EDGE_RISING
#define __IRQT_LOWLVL IRQ_TYPE_LEVEL_LOW
#define __IRQT_HIGHLVL IRQ_TYPE_LEVEL_HIGH
#define IRQT_NOEDGE (0)
#define IRQT_RISING (__IRQT_RISEDGE)
#define IRQT_FALLING (__IRQT_FALEDGE)
#define IRQT_BOTHEDGE (__IRQT_RISEDGE|__IRQT_FALEDGE)
#define IRQT_LOW (__IRQT_LOWLVL)
#define IRQT_HIGH (__IRQT_HIGHLVL)
#define IRQT_PROBE IRQ_TYPE_PROBE


/* 引脚信息 */
struct pin_desc{
    int irq;                   // 中断编号
    unsigned int  irq_ctl;     //触发中断状态
    char *name;                // 引脚名称
    unsigned int pin;          // 引脚编号
    unsigned int key_val;      // 对应键盘的A,B,C,D,E,F
};

/*
 * S3C2410_GPG 定义在arch/arm/mach-s3c24xx/include/mach/gpio-samsung.h
 */
static struct pin_desc pins_desc[6] = {
    {IRQ_EINT8, IRQT_BOTHEDGE, "K1", S3C2410_GPG(0), KEY_A},
    {IRQ_EINT11, IRQT_BOTHEDGE, "K2", S3C2410_GPG(3), KEY_B},
    {IRQ_EINT13, IRQT_BOTHEDGE, "K3", S3C2410_GPG(5), KEY_C},
    {IRQ_EINT14, IRQT_BOTHEDGE, "K4", S3C2410_GPG(6), KEY_D},
    {IRQ_EINT15, IRQT_BOTHEDGE, "K5", S3C2410_GPG(7), KEY_E},
    {IRQ_EINT19, IRQT_BOTHEDGE, "K6", S3C2410_GPG(11), KEY_F},
};


/* 定义一个input_dev结构体 */
struct input_dev *button_dev;
/* 保存dev_id,在定时器中用 */
struct pin_desc *button_id;
/* 定时器 */
static struct timer_list button_timer;

/*
 * 中断处理服务
 */
static irqreturn_t button_irq(int irq, void *dev_id)
{
    //保存当前的dev_id
    button_id =(struct ping_desc *)dev_id;
    //设置定时器值 10ms后执行，用于防止按键抖动
    mod_timer(&button_timer, jiffies+HZ/100 );

    return IRQ_RETVAL(IRQ_HANDLED);
}

/*
 * 定时器超时函数
 * 将输入转换为转换为统一事件形式
 */
static void button_timer_timeout(struct timer_list *t)
{
     //获取引脚电平
     int val = gpio_get_value(button_id->pin);
      if(val)        {
          /* 高电平,松开 上报事件*/
          input_event(button_dev, EV_KEY, button_id->key_val,  0);  //上报EV_KEY类型,按键值,0(没按下)
          input_sync(button_dev);         // 上传同步事件,告诉系统有事件出现
      }
      else  {
          /*  低电平，按下 上报事件*/
          input_event(button_dev, EV_KEY, button_id->key_val, 1);  //上报EV_KEY类型,按键值,1(按下)
          input_sync(button_dev);       // 上传同步事件,告诉系统有事件出现
      }
}

/* 
   GPG0、GPG3、GPG5、GPG6、GPG7、GPG11配置为中断功能 
   IRQ_EINTX 定义在 arch/arm/mach-s3c24xx/include/mach/irqs.h
*/
static int button_open(struct input_dev *dev)
{
    printk("register irq\n");
    int i,j,err;
    /* 注册中断 */
    for(i=0;i<6;i++){
       err = request_irq(pins_desc[i].irq, button_irq, pins_desc[i].irq_ctl, pins_desc[i].name, &pins_desc[i]);
       if(err < 0){
         for(j=0;j<i;j++){
            free_irq(pins_desc[j].irq, &pins_desc[j]);
         }
       }
    }

    return err;
}


/*
 * 卸载中断
 */
int button_close(struct input_dev *dev)
{
    printk("unregister irq\n");
    int i=0;
    for(i=0;i<6;i++){
       free_irq(pins_desc[i].irq, &pins_desc[i]);
    }

    return 0;
}

/*
 * 入口函数
 */
static int button_init(void)
{
    int err;
    printk("button driver init\n");

    /* 向内核 申请input_dev结构体 */
    button_dev = input_allocate_device();

    /* 设置input_dev */
    input_set_capability(button_dev,EV_KEY,KEY_A);   //支持按键 A
    input_set_capability(button_dev,EV_KEY,KEY_B);   //支持按键 B
    input_set_capability(button_dev,EV_KEY,KEY_C);   //支持按键 C
    input_set_capability(button_dev,EV_KEY,KEY_D);   //支持按键 D
    input_set_capability(button_dev,EV_KEY,KEY_E);   //支持按键 E
    input_set_capability(button_dev,EV_KEY,KEY_F);   //支持按键 F
    set_bit(EV_REP,button_dev->evbit);       //支持键盘重复按事件
    button_dev->open = button_open;          // 注册中断
    button_dev->close = button_close;        // 卸载中断

    /* 注册input_dev */
    err = input_register_device(button_dev);
    if (err) {
       printk("input button driver registration failed\n");
       /* 释放驱动结构体 */
       input_free_device(button_dev);
       return err;
    } else {
        printk("input button driver registered successfully\n");
    }

    /* 初始化定时器 */
    timer_setup(&button_timer,button_timer_timeout,0);
    add_timer(&button_timer);

    return 0;
}

/*
 * 出口函数
 */
static void __exit button_exit(void)
{
    printk("button driver exit\n");

     /* 删除定时器 */
    del_timer(&button_timer);
     /* 卸载类下的驱动设备 */
    input_unregister_device(button_dev);
    /* 释放驱动结构体 */
    input_free_device(button_dev);
    return;
}

module_init(button_init);
module_exit(button_exit);
MODULE_LICENSE("GPL");